package no.nordicsemi.android.nrfmesh.autobind;

import android.os.Handler;
import android.os.Looper;
import android.util.Log;
import android.widget.Toast;

import java.util.Map;

import no.nordicsemi.android.mesh.ApplicationKey;
import no.nordicsemi.android.mesh.MeshManagerApi;
import no.nordicsemi.android.mesh.MeshNetwork;
import no.nordicsemi.android.mesh.NetworkKey;
import no.nordicsemi.android.mesh.transport.ConfigAppKeyAdd;
import no.nordicsemi.android.mesh.transport.ConfigModelAppBind;
import no.nordicsemi.android.mesh.transport.Element;
import no.nordicsemi.android.mesh.transport.MeshModel;
import no.nordicsemi.android.mesh.transport.ProvisionedMeshNode;

/**
 *
 * Mesh 自动配置工具类（单例）：
 * - 初始化默认 AppKey（如果不存在）
 * - 在配网完成后自动将 AppKey 绑定到所有 Vendor Model
 * - 支持提示、重试、手动触发
 */
public class MeshAutoConfigurator {

    private static final String TAG = "MeshAutoConfigurator";
    private static MeshAutoConfigurator instance;

    private final MeshAutoConfigParams params = new MeshAutoConfigParams();
    private boolean retryOnFail = true; //  可选开启重试机制
    private final Handler retryHandler = new Handler(Looper.getMainLooper());

    private MeshAutoConfigurator() {}

    public static MeshAutoConfigurator getInstance() {
        if (instance == null) {
            instance = new MeshAutoConfigurator();
        }
        return instance;
    }

    public MeshAutoConfigParams getParams() {
        return params;
    }

    public void setRetryOnFail(boolean retry) {
        this.retryOnFail = retry;
    }

    /**
     * 初始化默认 AppKey（若不存在）
     */
    public void initDefaultAppKey(MeshManagerApi meshManagerApi) {
        //空置检查
        if (meshManagerApi == null) {
            Log.e(TAG, "MeshManagerApi 为空，无法初始化 AppKey");
            return;
        }

        MeshNetwork network = meshManagerApi.getMeshNetwork();
        if (network == null) {
            Log.e(TAG, "MeshNetwork 为空，无法初始化 AppKey");
            return;
        }

        if (network.getNetKeys().isEmpty()) {
            Log.e(TAG, "网络中没有 NetworkKey，无法创建 AppKey");
            return;
        }

        if (network.getAppKeys().isEmpty()) {
            Log.i(TAG, "未检测到 AppKey，自动添加默认 AppKey");

            NetworkKey netKey = network.getNetKeys().get(0);
            byte[] appKeyBytes = params.getDefaultAppKey();

            ApplicationKey appKey = new ApplicationKey(netKey.getKeyIndex(), appKeyBytes);
            appKey.setName("Default AppKey");

            try {
                boolean result = network.addAppKey(appKey);
                if (result) {
                    Log.i(TAG, " 默认 AppKey 添加成功");
                } else {
                    Log.w(TAG, " 默认 AppKey 添加失败（可能已存在）");
                }
            } catch (Exception e) {
                Log.e(TAG, "添加 AppKey 时异常: " + e.getMessage());
            }
        } else {
            Log.i(TAG, "已有 AppKey，跳过添加");
        }
    }

    /**
     * 自动绑定所有 Vendor Model（用于配网完成后）
     */
    public void autoBindAllVendorModels(ProvisionedMeshNode node, MeshManagerApi meshManagerApi) {
        bindInternal(node, meshManagerApi, false);
    }

    /**
     * 外部提供的手动重新绑定方法
     */
    public void manualRebindAllVendorModels(ProvisionedMeshNode node, MeshManagerApi meshManagerApi) {
        bindInternal(node, meshManagerApi, true);
    }

    /**
     * 内部绑定逻辑（可由自动或手动触发）
     */
    private void bindInternal(ProvisionedMeshNode node, MeshManagerApi meshManagerApi, boolean isManual) {
        if (meshManagerApi == null) {
            Log.e(TAG, "MeshManagerApi 为空，无法执行绑定");
            return;
        }

        if (node == null) {
            Log.e(TAG, "节点为空，无法执行绑定");
            return;
        }

        MeshNetwork network = meshManagerApi.getMeshNetwork();
        if (network == null) {
            Log.e(TAG, "MeshNetwork 为空，无法执行绑定");
            return;
        }

        if (network.getAppKeys().isEmpty()) {
            Log.e(TAG, "无法绑定，AppKey 尚未添加");
            return;
        }

        if (network.getNetKeys().isEmpty()) {
            Log.e(TAG, "无法绑定，NetworkKey 尚未添加");
            return;
        }

        final ApplicationKey appKey = network.getAppKeys().get(0); // 支持多个 AppKey 可扩展
        final int boundNetKeyIndex = appKey.getBoundNetKeyIndex();
        //边界检查
        if (boundNetKeyIndex >= network.getNetKeys().size()) {
            Log.e(TAG, "AppKey 绑定的 NetworkKey 索引超出范围: " + boundNetKeyIndex);
            return;
        }

        final NetworkKey netKey = network.getNetKeys().get(boundNetKeyIndex);
        final int dstAddress = node.getUnicastAddress();

        // 发送 ConfigAppKeyAdd 消息
        try {
            ConfigAppKeyAdd appKeyAdd = new ConfigAppKeyAdd(netKey, appKey);
            meshManagerApi.createMeshPdu(dstAddress, appKeyAdd);
            Log.i(TAG, String.format("发送 ConfigAppKeyAdd 消息到节点 0x%04X，AppKey: %s",
                    dstAddress, params.getDefaultAppKeyHex()));
        } catch (Exception e) {
            Log.e(TAG, "发送 ConfigAppKeyAdd 消息失败: " + e.getMessage(), e);
            return;
        }

        // 遍历所有 element
        int totalModels = 0;
        int vendorModels = 0;
        int boundModels = 0;

        for (Map.Entry<Integer, Element> entry : node.getElements().entrySet()) {
            final int elementAddress = entry.getKey();
            final Element element = entry.getValue();

            for (MeshModel model : element.getMeshModels().values()) {
                totalModels++;
                final int modelId = model.getModelId();

                // 判断是否是 Vendor Model（modelId 高 16 位不为 0 表示是 Vendor Model）
                if ((modelId & 0xFFFF0000) != 0x00000000) {
                    vendorModels++;
                    Log.i(TAG, String.format("绑定 Vendor Model [modelId=0x%08X, elementAddr=0x%04X]",
                            modelId, elementAddress));

                    ConfigModelAppBind bindMsg = new ConfigModelAppBind(
                            elementAddress,
                            modelId,
                            appKey.getKeyIndex()
                    );

                    try {
                        // 使用非确认消息避免超时问题，提高成功率
                        meshManagerApi.createMeshPdu(dstAddress, bindMsg);
                        boundModels++;
                        Log.i(TAG, "绑定成功: modelId=0x" + Integer.toHexString(modelId));
                    } catch (Exception e) {
                        Log.e(TAG, "绑定失败: " + e.getMessage());

                        //  如果启用重试机制，则延迟重试
                        if (retryOnFail) {
                            retryHandler.postDelayed(() -> {
                                try {
                                    meshManagerApi.createMeshPdu(dstAddress, bindMsg);
                                    Log.i(TAG, "重试绑定成功: modelId=0x" + Integer.toHexString(modelId));
                                } catch (Exception ex) {
                                    Log.e(TAG, "重试仍失败: " + ex.getMessage());
                                }
                            }, 300); //300ms后重试，不用Thread.sleep(300)，因为会阻塞主线程，而Handler是异步的
                        }
                    }
                }
            }
        }

        Log.i(TAG, String.format("绑定完成 - 总模型数: %d, Vendor模型数: %d, 成功绑定: %d",
                totalModels, vendorModels, boundModels));

        // 如果成功绑定了至少一个Vendor模型，则将节点标记为已配置
        if (boundModels > 0) {
            node.setConfigured(true);
            Log.i(TAG, "节点 " + node.getNodeName() + " 已标记为配置完成");
        } else {
            Log.w(TAG, "节点 " + node.getNodeName() + " 未成功绑定任何模型，保持未配置状态");
        }

        if (isManual) {
            Log.i(TAG, " 手动绑定流程完成");
        } else {
            Log.i(TAG, " 自动绑定流程完成");
        }
    }
}
